package com.ceo.common.aop;

import com.alibaba.fastjson.JSON;
import com.ceo.common.protocol.TraceSidConstants;
import com.ceo.common.utils.IdUtil;
import com.ceo.common.utils.IpUtils;
import com.ceo.common.utils.ServletUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;

/**
 * @author uto_dev_008
 * @desc
 * @since 2021/11/24 11:11
 * Copyright (c)  All rights reserved
 */
@Aspect
@Configuration
public class LogSidRecordAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogSidRecordAspect.class);

    /**
     * 换行符
     */
    private static final String LINE_SEPARATOR = System.lineSeparator();

    /**
     * 切点
     */
    @Pointcut("execution(* com.ceo..controller..*.*(..))")
    public void webLogAspect() {
    }

    /**
     * 环绕
     *
     * @param proceedingJoinPoint 切点
     * @return *
     * @throws Throwable *
     */
    @Around("webLogAspect()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        // 开始打印请求日志
        final HttpServletRequest request = ServletUtils.getRequest();

        String url = request.getRequestURL().toString();

        boolean isLog = getIsLog(url);

        if (isLog) {
            return proceedingJoinPoint.proceed();
        }

        String sid = request.getHeader(TraceSidConstants.HTTP_HEADER_TRACE_ID);
        if (StringUtils.isBlank(sid)) {
            sid = IdUtil.getSnowId();
        }
        MDC.put(TraceSidConstants.LOG_TRACE_ID, sid);
        // 请求的地址

        String ip = IpUtils.getIpAddr(request);
        logger.debug("\nURL   : {} , \nHTTP Method    : {},\nHTTP sid    : {},\nIP  : {} ,\nParams   :{}", request.getRequestURL().toString(), request.getMethod(), sid, ip, getRequestParams(request, proceedingJoinPoint));

        Exception exception = null;
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = proceedingJoinPoint.proceed();
        } catch (Exception e) {
            logger.error("exception      :{}", e);
            exception = e;
        } finally {
            long cost = System.currentTimeMillis() - startTime;
            //todo 需要对日志后续处理得时候用到
//            handleLog(proceedingJoinPoint, sysLog, exception, result);
            if (exception != null) {
                throw exception;
            }
            // 执行耗时
            logger.debug("Time-Consuming : {} ms", cost);
        }
        MDC.clear();
        return result;
    }

    private boolean getIsLog(String url) {
        boolean isLog = false;
        //todo 可以针对不需要打印日志url做处理
        return isLog;

    }

    private String getRequestParams(HttpServletRequest request, ProceedingJoinPoint joinPoint) {
        String method = request.getMethod();
        if (HttpMethod.PUT.name().equals(method) || HttpMethod.POST.name().equals(method)) {
            return argsArrayToString(joinPoint.getArgs());
        } else {
            Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            return paramsMap.toString();
        }

    }


    /**
     * 日志后续处理，可以入库，可以推到日志管理做后续追踪使用
     *
     * @param joinPoint
     * @param sysLog     记录日志得对象
     * @param e
     * @param jsonResult
     */
    protected void handleLog(final JoinPoint joinPoint, Object sysLog, final Exception e, Object jsonResult) {
        try {
//            final HttpServletRequest httpServletRequest = ServletUtils.getRequest();
//            final UserAgent userAgent = UserAgent.parseUserAgentString(httpServletRequest.getHeader("User-Agent"));
//            sysLog.setContentType(httpServletRequest.getContentType());
//            sysLog.setOs(userAgent.getOperatingSystem().getName());
//            sysLog.setBrowser(userAgent.getBrowser().getName());
//            // 获取当前的用户
//            UserVo user = ThreadEnvUtil.getUserObject();
//            // *========数据库日志=========*//
//            sysLog.setStatus(BusinessStatus.success.name());
//            String uri = httpServletRequest.getRequestURI();
//            sysLog.setUrl(uri);
//
//            if (user != null) {
//                user.setUserId(user.getId());
//            }
//
//            if (e != null) {
//                sysLog.setStatus(BusinessStatus.fail.name());
//                sysLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 5000));
//            }
//            // 设置方法名称
//            String className = joinPoint.getTarget().getClass().getName();
//            String methodName = joinPoint.getSignature().getName();
//            sysLog.setMethod(className + "." + methodName + "()");
//            // 设置请求方式
//            sysLog.setRequestType(httpServletRequest.getMethod());
//            // 保存request，参数和值
//            setRequestValue(joinPoint, sysLog);
//            // 保存response，参数和值
//            sysLog.setResponse(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 5000));
//            // 保存业务相关信息
//            setBizInfo(sysLog, httpServletRequest);
//            // 保存数据库
//            AsyncManager.me().execute(AsyncFactory.actionLog(sysLog));
        } catch (Exception exp) {
            // 记录本地异常日志
            logger.error("==前置通知异常==");
            logger.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }


    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray) {
        StringBuilder params = new StringBuilder();
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object o : paramsArray) {
                if (null != o && !isFilterObject(o)) {
                    try {
                        Object jsonObj = JSON.toJSON(o);
                        params.append(jsonObj.toString()).append(" ");
                    } catch (Exception e) {
                        logger.error("异常信息:{}", e.getMessage());
                    }
                }
            }
        }
        return params.toString().trim();
    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象，则返回true；否则返回false。
     */
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
                || o instanceof BindingResult;
    }
}
